package org.zoomdev.zoom.dao;

import org.zoomdev.zoom.common.utils.Page;
import org.zoomdev.zoom.dao.adapters.RecordAdapter;

import java.util.List;

/**
 * Entity active record
 */
public interface EAr<T> extends LambdaSql<T> {

    interface Condition<T> {
        void where(LambdaSql<T> ar);
    }

    EAr<T> select(SFunction<T, ?>... keys);


    @SuppressWarnings("unchecked")
    EAr<T> filter(SFunction<T, ?>... keys);


    EAr<T> where(EAr.Condition<T> condition);

    EAr<T> orWhere(EAr.Condition<T> condition);

    /**
     * 对字段进行筛选,用于select/update/insert
     *
     * @param filter
     * @return
     */
    EAr<T> filter(String filter);


    /**
     * 针对插入和更新有效
     *
     * @param value
     * @return
     */
    EAr<T> ignoreNull(boolean value);


    /**
     * 忽略掉实体类中的条件,默认不忽略，这在某些需要优化where条件的时候更加有效
     *
     * @return
     */
    EAr<T> ignoreEntityCondition();


    /**
     * 设置record适配器
     *
     * @param adapter
     * @return
     */
    EAr<T> adapter(RecordAdapter<T> adapter);


    /**
     * 凡是符合条件的都返回，需要确定返回的数据数量是少量的，否则引起程序运行慢
     *
     * @return
     */
    List<T> find();


    List<T> find(String sql, Object... args);


    List<T> limit(int position, int size);


    Page<T> position(int position, int size);


    Page<T> page(int page, int size);


    /**
     * 可定制的Page
     * <p>
     * Page只能统计总数量,如果在Page中需要获取其他统计数据，例如平均值等，则可做如下配置
     * 继承Page
     * <p>
     * class SomePage extends Page{
     *
     * @param pageClass
     * @param page
     * @param size
     * @param <P>
     * @return
     * @Column("avg(column_value_name)") private int value;
     * <p>
     * }
     * 其中column_value_name是数据库中的原始字段名称
     */
    <P extends Page> P page(Class<P> pageClass, int page, int size);


    /**
     * 在设置了数据的情况下
     *
     * @return
     */
    int update(T data);


    T get();

    /**
     * 根据主键查询,可以有多主键的情况,必须指定和主键相同个数的值
     *
     * @param values
     * @return
     */
    T get(Object... values);

    /**
     * 插入一个实体对象或者Record
     * 实体对象不必实现注册，但是最好开启启动注册检查
     *
     * @param data
     * @return
     */
    int insert(T data);


    /**
     * 删除实体
     *
     * @return
     */
    int delete(T data);

    /**
     * 获取记录数量           dao.ar(Book.class).count();/dar.ar("book").count()
     *
     * @return
     */
    int count();

    /**
     * 直接获取值            dao.ar(Book.class).where("id",1).getValue("id",String.class)
     *
     * @param key
     * @param typeOfE
     * @param <E>
     * @return
     */
    <E> E value(String key, Class<E> typeOfE);

    Entity getEntity();

    EAr<T> setEntity(Entity<T> entity);

    /**
     * 是否是严格模式，
     * 在严格模式下，update和insert每一个字段都会被检查，如果不存在则会报错
     * 而在非严格模式下，如果字段不存在，则会被过滤掉
     * <p>
     * 默认情况下是严格模式
     *
     * @param strict
     * @return
     */
    EAr<T> strict(boolean strict);


    int delete();

    /**
     * 批量插入
     *
     * @param it
     * @return
     */
    int[] insert(List<T> it);

    /**
     * 忽略重复插入,需要设置下重复插入的条件,最直接的办法就是指定下哪些键作为判断依据（必须unique约束）
     *
     * @return
     */
    int insertIgnoreDuplicated(T data, String... keys);

    /**
     * 插入或者更新,最直接的办法就是指定下哪些键作为判断依据（必须unique约束）
     *
     * @return
     */
    int insertOrUpdate(T data, String... keys);

    /**
     * 批量更新
     *
     * @param it
     * @return
     */
    int update(Iterable<T> it);

    int delete(Iterable<T> it);

    EAr<T> rawMode();
}
